
#include "index_builder.h"

IndexBuilder::IndexBuilder(std::string indexDB, std::string docDB)
        : indexDBPath_(indexDB), docDBPath_(docDB), index_(1)
{}

IndexBuilder::~IndexBuilder()
{}

int IndexBuilder::LoadDB()
{
    indexMgr_.LoadDB(indexDBPath_);
    docMgr_.LoadDB(docDBPath_);
    return 0;
}

int IndexBuilder::AddDoc(std::string &title, std::string &body)
{
    // 保存文档
    docMgr_.WriteDoc(title, body);

    // 生成该文件倒排列表保存到内存倒排列表
    int docID = docMgr_.GetDocID(title);
    ParseDoc(docID, body);

    // 超过阈值倒排列表写入磁盘
    if (index_.IsFull()) {
        auto it = index_.Begin();
        while (it != index_.End()) {
            UpdatePosting(it->second);
            ++it;
        }
        index_.Clear();
    }

    return 0;
}

int IndexBuilder::ParseDoc(int docID, std::string &body)
{
    InvertedIndex index;
    std::string token;
    int pos = 0;

    // 创建单个文档的倒排列表
    pos = 0;
    while (NgramNext(body, token, pos) != 0) {
        index.AddPosting(token, docID, pos);
        pos += token.size();
    }
    index.AddDoc(1);

    // 合并文档倒排列表到内存中倒排列表
    index_.MergeIndex(index);
    return 0;
}

int IndexBuilder::NgramNext(const std::string &body, std::string &token, int &pos)
{
    token = "";

    int p = pos;
    while (p < body.size() && !std::isalnum(body[p])) {
        ++p;
    }

    pos = p;
    int n = 0;
    while (p + n < body.size() && std::isalnum(body[p + n])) {
        token.push_back(body[p + n]);
        ++n;
    }
    return n;
}

int IndexBuilder::UpdatePosting(PostingList &memLst)
{
    std::string token = memLst.GetToken();
    PostingList diskLst = indexMgr_.GetPosting(token);

    diskLst.MergePosing(memLst);
    indexMgr_.WriteList(diskLst);

    return 0;
}
